﻿
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace WSU.ChekaParallel.TestTask
{
    static class TestChildTask
    {
        private static void TestWaitChildTask()
        {
            Task parentTask = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("Parent Task Completed.");

                // ================== spawn detached child task
                Task.Factory.StartNew(() =>
                {
                    Thread.Sleep(1000);
                    Console.WriteLine("Detached Child Task Completed.");
                });

                // ================== spawn attached child task
                // ================== then when the parent task completes only when all its attached children tasks complete
                Task.Factory.StartNew(() =>
                {
                    Thread.Sleep(500);
                    Console.WriteLine("Attached Child Task Completes.");
                }, TaskCreationOptions.AttachedToParent);
            });

            parentTask.Wait();// it will wait until all attached children tasks are done
            Console.WriteLine("------------------ parent task is totally finished.");

            Console.WriteLine("Press any key to exit, ......");
            Console.ReadLine();
        }

        private static void PrintNestExceptions(this AggregateException aexp)
        {
            foreach (Exception innerExcep in aexp.InnerExceptions)
            {
                if (innerExcep is AggregateException)
                    PrintNestExceptions((AggregateException)innerExcep);
                else
                    Console.WriteLine("[{0}]: {1}", innerExcep.Source, innerExcep.Message);
            }
        }

        private static void TestChildTaskException()
        {
            Task parentTask = Task.Factory.StartNew(() =>
            {
                // -------------------- child task
                Task.Factory.StartNew(() =>
                {
                    // -------------------- grandchild task
                    Task.Factory.StartNew(() =>
                    {
                        throw new NotImplementedException { Source = "grandchild task" };
                    }, TaskCreationOptions.AttachedToParent);
                    throw new InvalidOperationException { Source = "child task" };
                }, TaskCreationOptions.AttachedToParent);
            });

            try
            {
                // will wait any level child task (whether child or grandchild)
                parentTask.Wait();
            }
            catch (AggregateException aexp)
            {
                // when parent catches exceptions from child, what it catches is never common, individual exception
                // but always aggregated exceptions
                // aexp.PrintNestExceptions();
                // use "Flatten" here to remove the hierarchy architecture of nested AggregateException
                foreach (Exception innerExcep in aexp.Flatten().InnerExceptions)
                {
                    Console.WriteLine("Source[{0}], Message='{1}'", innerExcep.Source, innerExcep.Message);
                }
            }
        }

        private static void TestParentTaskStatus()
        {
            Task<int> parentTask = Task.Factory.StartNew(() =>
            {
                Task.Factory.StartNew(() =>
                                          {
                                              Console.WriteLine("Press ENTER to complete child task,......");
                                              Console.ReadLine();
                                          }, TaskCreationOptions.AttachedToParent);
                return 88;
            });

            Thread.Sleep(TimeSpan.FromSeconds(0.1));
            Debug.Assert(parentTask.Status == TaskStatus.WaitingForChildrenToComplete);
            Console.WriteLine("ParentTask's status='{0}'", parentTask.Status);

            Console.WriteLine("finally, ParentTask totally completes with result={0}", parentTask.Result);
            Debug.Assert(parentTask.Status == TaskStatus.RanToCompletion);
        }

        private static void TestContinueWithChild(TaskContinuationOptions childContinueOption)
        {
            Task parent = Task.Factory.StartNew(() =>
            {
                Task childTask = Task.Factory.StartNew(() =>
                                                           {
                                                               Thread.Sleep(1000);
                                                               Console.WriteLine("child task completes");
                                                           }, TaskCreationOptions.AttachedToParent);
                Task childContinuation = childTask.ContinueWith(antecedent =>
                                                                    {
                                                                        Thread.Sleep(500);
                                                                        Console.WriteLine("child's continuation completes");
                                                                    }, childContinueOption);
            });

            parent.Wait();
            Console.WriteLine("!!!!!!!!!!!!!! parent task completes");

            Helper.Pause();
        }

        public static void TestMain()
        {
            // TestWaitChildTask();
            // TestChildTaskException();
            // TestParentTaskStatus();
            // TestContinueWithChild(TaskContinuationOptions.None);
            TestContinueWithChild(TaskContinuationOptions.AttachedToParent);
        }
    }
}